﻿//PnLManager.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Algo.PnL
{
	using System;
	using System.Collections.Generic;
	using System.Linq;

	using Ecng.Collections;

	using StockSharp.BusinessEntities;

	/// <summary>
	/// Менеджер прибыли-убытка.
	/// </summary>
	public class PnLManager : IPnLManager
	{
		private readonly Dictionary<MyTrade, MyTradePnLInfo> _tradeInfos = new Dictionary<MyTrade, MyTradePnLInfo>(); 
		private readonly SynchronizedDictionary<Security, PnLQueue> _securityPnLs = new SynchronizedDictionary<Security, PnLQueue>();

		/// <summary>
		/// Создать <see cref="PnLManager"/>.
		/// </summary>
		public PnLManager()
		{
		}

		/// <summary>
		/// Суммарное значение прибыли-убытка.
		/// </summary>
		public virtual decimal PnL
		{
			get { return RealizedPnL + GetUnrealizedPnL(); }
		}

		private decimal _realizedPnL;

		/// <summary>
		/// Относительное значение прибыли-убытка без учета открытой позиции.
		/// </summary>
		public virtual decimal RealizedPnL
		{
			get { return _realizedPnL; }
		}

		/// <summary>
		/// Обнулить <see cref="PnL"/>.
		/// </summary>
		public void Reset()
		{
			_realizedPnL = 0;
			_securityPnLs.Clear();
		}

		/// <summary>
		/// Рассчитать прибыльность сделки. Если сделка уже ранее была обработана, то возвращается предыдущая информация.
		/// </summary>
		/// <param name="trade">Сделка.</param>
		/// <returns>Информация о новой сделке.</returns>
		public virtual MyTradePnLInfo ProcessMyTrade(MyTrade trade)
		{
			if (trade == null)
				throw new ArgumentNullException("trade");

			lock (_securityPnLs.SyncRoot)
			{
				return _tradeInfos.SafeAdd(trade, key =>
				{
					var queue = _securityPnLs.SafeAdd(trade.Trade.Security, security => new PnLQueue(security));

					var info = queue.Process(trade, true);

					_realizedPnL += info.PnL;
					return info;
				});
			}
		}

		private decimal GetUnrealizedPnL()
		{
			return _securityPnLs.SyncGet(d => d.Sum(p => p.Key.MinStepPrice / p.Key.MinStepSize * p.Value.UnrealizedPnL));
		}
	}
}